const fs = require('fs-extra');
const path = require('path');
const { createPluginContainer } =  require('../server/pluginContainer');
const resolvePlugin =  require('../plugins/resolve.js');

const htmlTypesRe = /\.html$/;
const scriptModuleRE = /<script src="(.+?)" type="module"><\/script>/;
const JS_TYPES_RE = /\.js$/;

async function esBuildDepPlugin(config, deps){
  config.plugins = [
    resolvePlugin(config)
  ];
  const container = await createPluginContainer(config);

  const resolve = async (id/*绝对路径*/, importer) => {
    return await container.resolveId(id, importer);
  };

  return {
    name: 'vite:dep-scan',
    setup(build){
      //onResolve用来处理路径的
      //可以设置多个 会执行匹配到的第一个
      //处理html的路径
      build.onResolve({filter:htmlTypesRe},async ({path/*要引入的模块的路径*/,importer/*引入的模块*/})=> {
        console.log('1 htmlTypesRe onResolve 先走这里');

        console.log('path:', path); //path: F:\code\js_workplace\tutorial\vite_tutorial\99.mini-vite\relative-point\index.html
        console.log('importer:', importer); //importer:

        const resolved = await resolve(path, importer);
        if (resolved) {

          //把结果向后传递, 我们会在相匹配的filter和namespace的build.onLoad中继续处理
          return {
            path: resolved.id || resolved,
            namespace: 'html' //为诶了更细化区分不同的文件类型, 我可以给文件添加一个命名空间
          }
        }
      });

      //处理其它文件类型的路径
      build.onResolve({ filter: /.*/ }, async ({ path, importer }) => {
        console.log('3 filter: /.*/ onResolve 再走这里');
        console.log('path:',path)
        console.log('importer:',importer)

        const resolved = await resolve(path, importer)
        if (resolved) {
          //返回值可能是 {id:xx} 或 xx
          const id = resolved.id || resolved;
          const included = id.includes('node_modules');
          if (included) {
            //deps.vue = F:/code/js_workplace/tutorial/vite_tutorial/99.test-mini-vite-project/node_modules/vue/dist/vue.runtime.esm-bundler.js
            deps[path] = id;
            return {
              path: id,
              external: true //external为true ---> 说明是一个外部模块, 就不会进行后续的打包分析了, 直接返回了 // 否则还会根据vue.runtime.esm-bundler.js解析到 node_modules\\@vue\\runtime-dom\\dist\\runtime-dom.esm-bundler.js 等模块
            }
          }
          return {
            path: id
          }
        }
        return { path }
      });


      //用来处理读取内容
      //会解析html中<script type=module src=xxx>标签, 会将其转译为 import xxx
      build.onLoad({
        filter: htmlTypesRe,
        namespace: 'html'
      }, async ({path}) => {
        console.log('2 htmlTypesRe onLoad 再走这里');
        console.log('path:',path)

        let html = fs.readFileSync(path, 'utf-8');
        let [, scriptSrc] = html.match(scriptModuleRE);
        let js = `import ${JSON.stringify(scriptSrc)}`; // <script src="/src/main.js" type="module"></script> ---> import '/src/main.js'

        //把转换后的结果向后传递 告诉esbuild用js loader进行处理
        //esbuild默认支持的类型(loader) 查看 https://esbuild.github.io/content-types/
        //每种content-type 对应 一种loader
        return {
          loader: 'js',
          contents: js
        };
      });

      build.onLoad({
        filter: JS_TYPES_RE,
      }, async ({path: id }) => {
        console.log('4 JS_TYPES_RE onLoad 再走这里');
        console.log('path:',id)

        let ext = path.extname(id).slice(1); // .js --> js
        const contents = fs.readFileSync(id, 'utf8');
        return {
          loader: ext,
          contents
        }
      });
    }
  }
}

exports.esBuildDepPlugin = esBuildDepPlugin;
